use Net::SFTP::Foreign;
use Fcntl ':mode';

my $host = "192.168.4.84";

my %args = (
    user => "etl",
    password => "etl",
    port => 22,
);

my $bass1_ftp_basedir = ""; 

sub test2 {
    my ($host, $args) = @_;
    my $path = "/home/etl";

    my $sftp = Net::SFTP::Foreign->new($host, %$args);
    $sftp->die_on_error("Unable to establish SFTP connection");
    
    $sftp->setcwd($path) or die "unable to change cwd: " . $sftp->error;

    my $ls = $sftp->ls("/home/etl") or die "unable to retrieve directory: ".$sftp->error;;
    # print "$_->{filename}\n" for (@$ls);
    
    # for my $file (@$ls) {
    #     print $file->{longname}."\n";
    # }
    
    # print $$ls[0]{longname};
    
    my @srcfilelist;
    
    for my $file (@$ls) {
        push(@srcfilelist, $file->{longname});
    }

    print $_."\n" for(@srcfilelist);

}

# test2($host, \%args);

sub showTime
{
   	my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time());
   	my $current = "";

   	$hour = sprintf("%02d", $hour);
   	$min  = sprintf("%02d", $min);
   	$sec  = sprintf("%02d", $sec);

   	$current = "${hour}:${min}:${sec}";
	  print "[$current] ";
   	return $current;
}

sub Ftp_Connect
{
	my($protocol,$ftpserver,$port,$logon_ftp,$Is_Pasv,$try_limit) = @_;
	my $USER="";
	my $PASSWD="";
	unless(@_ == 6 or @_ == 5 or @_ == 4 or @_ == 3)
	{
		print "The paras are not right\n";
		return undef;
	}

	$try_limit = 5 unless($try_limit);
	print "EDTFTPCONNECT:$ftpserver,$port,$logon_ftp,$Is_Pasv,$try_limit\n";
	($USER, $PASSWD) = split(':' , $logon_ftp);
  	print "password:$USER, $PASSWD\n";

	my $ftp = ();
	my $i = 0;
  	if ($Is_Pasv eq "Y")
  	{
		$Is_Pasv=1;
  	}
  	else
	{
		$Is_Pasv=0;
	}

	if ($protocol eq "FTP") {
		while(!defined($ftp))
		{
			print "connecting ftpserver...\n";
			$ftp=Net::FTP->new($ftpserver,Debug => 0, Timeout => 600,Port=>$port, Passive => $Is_Pasv) ;
			#print "FTP->NEW:$ftp...\n";
			if(!defined($ftp))
			{
				$i++;
				#email()if($i==$try_limit);
				print "Try again $i times.\n";
				if($i==$try_limit)
				{
					showTime();print "Unable to connect ftp Server[$ftpserver], Reach FTP Connect Max Try Limit...\n";
					return undef;
				}

				sleep 3;
			}
		}

		my $rc = 0;
		$i = 0;
		while(!$rc)
		{
			#showTime();print "Connect to ftp Server Current User : [$USER]\n";
			$rc=$ftp->login("$USER","$PASSWD");
			print "login value:$rc\n";
			if(!$rc)
			{
				showTime();print "Unable Connect to ftp Server[$ftpserver] :",$ftp->message;
				print "\n";
				$i++;
				if($i==$try_limit)
				{
					showTime();print "Unable to connect ftp Server[$ftpserver], Reach FTP Connect Max Try Limit...\n";
					return undef;
				}
				sleep 3;
			}
			else
			{
				$ftp->binary();
			}
		}
	} elsif ($protocol eq "SFTP") {
		while(!defined($ftp))
		{
			showTime();print "connecting sftpserver...\n";
            my %args = (user => $USER, password => $PASSWD, port => $port,);
			$ftp = Net::SFTP::Foreign->new($ftpserver, %args);
			if(!defined($ftp))
			{
				$i++;
				print "Try again $i times.\n";
				if($i==$try_limit)
				{
					showTime();print "Unable to connect ftp Server[$ftpserver], Reach FTP Connect Max Try Limit...\n";
					return undef;
				}
				sleep 3;
			}
		}
	}
	
   	return $ftp;
}

# my $login_ftp = $args{user}.":".$args{password};
# print "login_ftp:". $login_ftp . "\n";
# my $sftp = Ftp_Connect("SFTP", $host, $args{port}, $login_ftp);
# print "sftp:". $sftp . "\n";
sub FTP_get_info
{   #从远端服务器$ftp，对应目录$des_dir中，找到相应文件$fileclass。
	# 根据$sleepflag标识，0：直接传输；1：间隔1秒取两次实际字节，判断字节数不再1秒内发生变化的进行传输；2：与控制文件中数据文件字节数$CTLfilesize，匹配进行传输；确认传输，返回文件字节数；
	my($protocol,$ftp,$des_dir,$fileclass,$sleepflag,$CTLfilesize) = @_;
	unless(@_ == 5 or @_ == 6)
	{
		showTime();print "FTP_get_info parameter is not right\n";
		return -1;
	}
	
	if (!$CTLfilesize){
		$CTLfilesize=0;
	}
	else {
		#print "CTLfilesize:$CTLfilesize\n";
	}
	chomp($fileclass);
	my $testsize1;
	my $testsize2;
	my @srcfilelist1;
	my @srcfilelist2;
	my $filetype;
	my $cwd_rc;
    my $ftpmsg;
	if ($protocol eq "FTP") {
		$ftp->cwd("$des_dir");
	    $ftpmsg = $ftp->message;
    } elsif ($protocol eq "SFTP") {
		$ftp->setcwd("$des_dir");
        $ftpmsg = $ftp->error;
        if ($ftpmsg == 0) {
            $cwd_rc = 1;
        }
	} 
	
	if (!$cwd_rc )
	{
		showTime();print "Can't FIND Direcotry $des_dir:$ftpmsg\n";
		return -1;
	}

	#获取文件信息
	my $flag =0;
	
	if ($protocol eq "FTP") {
		$flag = eval{
				@srcfilelist1 = $ftp->dir("${fileclass}");
			};
	} elsif ($protocol eq "SFTP") {
		$flag = eval{
                my $ls = $ftp->ls(".", wanted => qr /^${fileclass}$/);
                for my $file (@$ls) {
                    push(@srcfilelist1, $file->{longname});
                }
			};
	}
	if ($flag==2 || !@srcfilelist1){
		showTime();print "The File $fileclass is not exists!\n";
		return -2;
	}

	unless(!$@)
	{
		showTime();print "List Direcotry Failed:$@\n";
		return -2;
	}
	$testsize1=(split(' ',$srcfilelist1[0]))[4]; #2
	$filetype=substr((split(' ',$srcfilelist1[0]))[0],1,1);

	#[2].进行与控制文件字节数进行比对校验，效率较高
	if ($sleepflag==2 && @_ == 5){
		if ($testsize1 eq $CTLfilesize){
			return $testsize1;
		}
		else {
			return -1;
		}
	}

	#[0].不校验字节数，直接传输。
	if ($sleepflag==0)
	{
		return $testsize1;
	}

	#[1].进行文件sleep方式校验，因下载需时间等待，会减慢传输效率。
	sleep(1);
	
	if ($protocol eq "FTP") {
		$flag = eval{
				@srcfilelist2 = $ftp->dir("${fileclass}");
			};
	} elsif ($protocol eq "SFTP") {
		$flag = eval{
				my $ls = $ftp->ls(".", wanted => qr /^${fileclass}$/);
                for my $file (@$ls) {
                    push(@srcfilelist2, $file->{longname});
                }
			};
	}
	unless(!$@)
	{
		showTime();print "List Direcotry Failed:$@\n";
		return -2;
	}
	$testsize2=(split(' ',$srcfilelist2[0]))[4]; #2
	if ($testsize1 != $testsize2){
		return -1;
	}
	return $testsize1;
}


# my $login_ftp = $args{user}.":".$args{password};
# print "login_ftp:". $login_ftp . "\n";
# my $sftp = Ftp_Connect("SFTP", $host, $args{port}, $login_ftp);

# my $size = FTP_get_info("SFTP", $sftp, "/home/etl", "cv_debug.log", 1);
# print "size:". $size . "\n";


sub FTP_get_list
{
	my($protocol,$ftp,$des_dir,$fileclass) = @_;
	unless(@_ == 4 or @_ == 3)
	{
		showTime();print "parameter is not right\n";
		return 0;
	}

	if (@_ == 3){
		$fileclass=" ";
	}

	my @filelist;

	my $dir;
    my $cwd_rc;
    my $ftpmsg;
    if ($protocol eq "FTP") {
        $dir = $ftp->pwd;
        $cwd_rc =$ftp->cwd("$bass1_ftp_basedir/$des_dir");
        $ftpmsg = $ftp->message;
    } elsif ($protocol eq "SFTP") {
        $dir = $ftp->cwd;
        $cwd_rc = $ftp->setcwd("$bass1_ftp_basedir/$des_dir");
        $ftpmsg = $ftp->error;
    }
    
    if (!$cwd_rc )
    {
        showTime();#print "Can't FIND Direcotry $des_dir:$ftpmsg\n";
        print "Can't FIND Direcotry $des_dir\n";
        return 0;
    }

	#获取文件列表
	my $flag = 0;
    if ($protocol eq "FTP") {
        $flag = eval{
                @filelist = $ftp->ls("$fileclass");
            };
    } elsif ($protocol eq "SFTP") {
        if ($fileclass eq " ") {
            $flag = eval{
                my $ls = $ftp->ls(".", wanted => sub {
                            my $entry = $_[1];
                            S_ISREG($entry->{a}->perm)
                        });
                for my $file (@$ls) {
                    push(@filelist, $file->{filename});
                }
            };
        } else {
            $flag = eval{
                my $ls = $ftp->ls(".", wanted => qr /^${fileclass}$/);
                for my $file (@$ls) {
                    push(@filelist, $file->{filename});
                }
            };
        }
    }


	unless(!$@)
	{
		showTime();print "List Direcotry Failed:$@\n";
		return 0;
	}

	return \@filelist;
}


# my $login_ftp = $args{user}.":".$args{password};
# print "login_ftp:". $login_ftp . "\n";
# my $sftp = Ftp_Connect("SFTP", $host, $args{port}, $login_ftp);

# # my $fileList = FTP_get_list("SFTP", $sftp, "/home/etl", "cv_debug.log");
# my $fileList = FTP_get_list("SFTP", $sftp, "/home/etl");
# print "file:". $_ . "\n" for (@$fileList);

sub FTP_get_long_list
{   #从远端服务器$ftp获取相应目录$des_dir中，符合模式$model的文件列表，列表以全路径体现
	my($protocol,$ftp,$des_dir,$model,$fileclass) = @_;
	unless(@_ == 5 or @_ == 4)
	{
		showTime();print "FTP_get_long_list parameter is not right\n";
		return 0;
	}

	if (@_ == 4){
		$fileclass=" ";
	}

	my @srcfilelist;
	my @dealfilelist;

    my $dir;
    my $cwd_rc;
    my $ftpmsg;
    if ($protocol eq "FTP") {
        $dir = $ftp->pwd;
        $cwd_rc =$ftp->cwd("$bass1_ftp_basedir/$des_dir");
        $ftpmsg = $ftp->message;
    } elsif ($protocol eq "SFTP") {
        $dir = $ftp->cwd;
        $cwd_rc = $ftp->setcwd("$bass1_ftp_basedir/$des_dir");
        $ftpmsg = $ftp->error;
    }

	if (!$cwd_rc )
	{
		showTime();print "Can't FIND Direcotry $des_dir:$ftpmsg\n";
		return 0;
	}
	#获取文件列表
	my $flag = 0;
    if ($protocol eq "FTP") {
        $flag = eval{
                @srcfilelist = $ftp->dir("$fileclass");
            };
    } elsif ($protocol eq "SFTP") {
        if ($fileclass eq " ") {
            $flag = eval{
                my $ls = $ftp->ls(".", wanted => sub {
                            my $entry = $_[1];
                            S_ISREG($entry->{a}->perm)
                        });
                for my $file (@$ls) {
                    push(@srcfilelist, $file->{longname});
                }
            };
        } else {
            $flag = eval{
                my $ls = $ftp->ls(".", wanted => qr /^${fileclass}$/);
                for my $file (@$ls) {
                    push(@srcfilelist, $file->{longname});
                }
            };
        }
    }

	if ($#srcfilelist==0)
	{
		showTime();print "List Direcotry Failed:$@\n";
		return 0;
	}
	chomp(@srcfilelist);
	foreach(@srcfilelist){
		my @dirfilemap=split(' ',$_);
		if ($dirfilemap[0] eq "total" || $dirfilemap[0] eq "." || $dirfilemap[0] eq ".."){next;}
		my $filename=$dirfilemap[8]; #3
		my $filesize=$dirfilemap[4]; #2
		
		chomp($filename);
		if ($filename =~ m/^$model$/){
			push (@dealfilelist,"$filename")
		}
	}
	return \@dealfilelist;
}

# my $login_ftp = $args{user}.":".$args{password};
# print "login_ftp:". $login_ftp . "\n";
# my $sftp = Ftp_Connect("SFTP", $host, $args{port}, $login_ftp);

# my $fileList = FTP_get_long_list("SFTP", $sftp, "/home/etl", ".*", "cv_debug.log");
# # my $fileList = FTP_get_long_list("SFTP", $sftp, "/home/etl", ".*");
# print "file:". $_ . "\n" for (@$fileList);

sub FTP_put_file
{
    my($protocol,$ftp,$des_dir,$des_file,$remote_dir) = @_;

	my $pass_rc=0;

	unless(@_ == 5)
	{
		showTime();print "parameter is not right\n";
		return 1;
	}

	unless($remote_dir =~ m'^/.*')
	{
		$remote_dir = "$remote_dir";
	}

    if ($protocol eq "FTP") {
        $rc = $ftp->cwd("$remote_dir");
        $ftpmsg = $ftp->message;
    } elsif ($protocol eq "SFTP") {
        $rc = $ftp->setcwd("$remote_dir");
        $ftpmsg = $ftp->error;
    }

    if (!$rc )
    {
	 	showTime();print "Can't FIND Direcotry $des_dir:$ftpmsg\n";
	 	return 0;
	}
	my $rdir;
    if ($protocol eq "FTP") {
        $rdir = $ftp->pwd;
    } elsif ($protocol eq "SFTP") {
        $rdir = $ftp->cwd;
    }
    
	showTime();print "remote dir is $rdir \n";

	showTime();print "open $des_file to upload file \n";

	my $pass_ret;
    if ($protocol eq "FTP") {
        $pass_ret = $ftp->put("$des_dir/$des_file");
        $ftpmsg=$ftp->message;
    } elsif ($protocol eq "SFTP") {
        $pass_ret = $ftp->put("$des_dir/$des_file");
        $ftpmsg=$ftp->error;
    }
    
	showTime();print "put $des_dir/$des_file msg: $ftpmsg. \n";
	if(defined($pass_ret))
    {
	 	showTime();print "File $des_file pass successful.\n";
	 	$pass_rc=0;
	}
	return $pass_rc;
}

# my $login_ftp = $args{user}.":".$args{password};
# print "login_ftp:". $login_ftp . "\n";
# my $sftp = Ftp_Connect("SFTP", $host, $args{port}, $login_ftp);

# my $putFullFile = FTP_put_file("SFTP", $sftp, "/lyndon/iProject/perlpath/edt/EDT/temp", "cv_debug.log", "/home/etl/Backup");
# print "putFullFile:". ${putFullFile} . "\n";


sub FTP_get_file
{
	my($protocol,$ftp,$des_dir,$des_file,$local_dir) = @_;
	unless(@_ == 5)
	{
		print "parameter is not right\n";
		return "FALSE";
	}

	unless($des_dir =~ m'^/.*')
	{
		$des_dir = "$des_dir";
	}

	my $cwd_rc;
	my $ftpmsg;

    if ($protocol eq "FTP") {
	    $cwd_rc = $ftp->cwd("$bass1_ftp_basedir/$des_dir");
	    $ftpmsg = $ftp->message;
    } elsif ($protocol eq "SFTP") {
        $cwd_rc = $ftp->setcwd("$bass1_ftp_basedir/$des_dir");
        $ftpmsg = $ftp->error;
    }

    if (!$cwd_rc )
    {
	 	showTime();print "Can't FIND Direcotry $des_dir:$ftpmsg\n";
	 	return "FALSE";
	}

    my $get_rc;
    if ($protocol eq "FTP") {
        $get_rc = $ftp->get("$des_file","$local_dir/$des_file");
    } elsif ($protocol eq "SFTP") {
        $get_rc = $ftp->get("$des_file","$local_dir/$des_file")
    }
	

	unless($get_rc)
	{
		print "File $des_file get failed:$!\n";
		return "FALSE";
	}

	return "$local_dir/$des_file";
}


# my $login_ftp = $args{user}.":".$args{password};
# print "login_ftp:". $login_ftp . "\n";
# my $sftp = Ftp_Connect("SFTP", $host, $args{port}, $login_ftp);

# my $getFullFile = FTP_get_file("SFTP", $sftp, "/home/etl", "cv_debug.log", "/lyndon/iProject/perlpath/edt/EDT/temp");
# print "getFullFile:". ${getFullFile} . "\n";


sub FTP_Up_File
{
	my($protocol,$ftp,$des_dir,$des_file,$remote_dir) = @_;
	print "上传文件： $des_file\n";
	unless(@_ == 5)
	{
		showTime();print "parameter is not right\n";
		return 1;
	}

	unless($remote_dir =~ m'^/.*')
	{
		$remote_dir = "$remote_dir";
	}

	if(!open(FH,"$des_dir/$des_file"))
	{
		print "Can't open file $des_dir/$des_file:$!\n";
		return 1;
    }

	my @info = <FH>;
	close(FH);

    my $rc;
    my $ftpmsg;
    if ($protocol eq "FTP") {
	    $rc = $ftp->cwd("$bass1_ftp_basedir/$remote_dir");
	    $ftpmsg = $ftp->message;
    } elsif ($protocol eq "SFTP") {
        $rc = $ftp->setcwd("$bass1_ftp_basedir/$remote_dir");
        $ftpmsg = $ftp->error;
    }

    if (!$rc)
    {
	 	showTime();print "Can't FIND Direcotry $des_dir:$ftpmsg\n";
	 	return 0;
	}
	my $rdir;
    if ($protocol eq "FTP") {
        $rdir = $ftp->pwd;
    } elsif ($protocol eq "SFTP") {
        $rdir = $ftp->cwd;
    }
	showTime();print "remote dir is $rdir \n";

	showTime();print "open $des_file to upload file \n";
	#检查文件名和内容是否正确
	my $i;
	my $pass_rc=0;
	foreach $i ( @info)
	{

        my $filename=(split(' ',$i))[0];
        $filename=~s/\s+//;
        my ($fileprefix,$fileext)=split('\.',$filename);
        $fileprefix=~s/\s+//;
        my $tmp_filename=$fileprefix."\.tmp";
        if ($protocol eq "FTP") {
            $pass_ret = $ftp->put("$des_dir/$filename","$tmp_filename");
            $ftpmsg=$ftp->message;
        } elsif ($protocol eq "SFTP") {
            $pass_ret = $ftp->put("$des_dir/$filename","$tmp_filename");
            $ftpmsg=$ftp->error;
        }
        if(defined($pass_ret))
        {
            showTime();print "File $filename pass successful.\n";
            if ($protocol eq "FTP") {
                $ftp->rename("$tmp_filename","$filename");
            } elsif ($protocol eq "SFTP") {
                $ftp->rename("$tmp_filename","$filename");
            }
        }
        else
        {
            showTime();print "File $filename pass failed:$!\n";
            $pass_rc=$pass_rc+1;
        }
        showTime();print "put $des_dir/$filename msg:$ftpmsg. \n";
	}

	if (  $pass_rc == 0 )
	{
       	my $pass_ret;
        my $ftpmsg;
        if ($protocol eq "FTP") {
            $pass_ret = $ftp->put("$des_dir/$des_file");
            $ftpmsg=$ftp->message;
        } elsif ($protocol eq "SFTP") {
            $pass_ret = $ftp->put("$des_dir/$des_file");
            $ftpmsg=$ftp->error;
        }

	   showTime();print "put $des_dir/$des_file msg: $ftpmsg. \n";
	   if(defined($pass_ret))
   	   {
	    	showTime();print "File $des_file pass successful.\n";
	    	$pass_rc=0;
	   }
	   else
	   {
	    	showTime();print "File $des_file pass failed:$!\n";
	    	$pass_rc=1;
	   }
	}

	return $pass_rc;

}

# my $login_ftp = $args{user}.":".$args{password};
# print "login_ftp:". $login_ftp . "\n";
# my $sftp = Ftp_Connect("SFTP", $host, $args{port}, $login_ftp);

# my $getFullFile = FTP_Up_File("SFTP", $sftp, "/lyndon/iProject/perlpath/edt/EDT/temp", "dir.hdc_20170905", "/home/etl/Backup");
# print "getFullFile:". ${getFullFile} . "\n";


sub FTP_del_file
{
	my($protocol,$ftp,$des_dir,$des_file) = @_;
	unless(@_ == 4)
	{
		print "parameter is not right\n";
		return 0;
	}

	unless($des_dir =~ m'^/.*')
	{
		$des_dir = "$des_dir";
	}

    my $cwd_rc;
    my $ftpmsg;
    if ($protocol eq "FTP") {
	    $cwd_rc = $ftp->cwd("$bass1_ftp_basedir/$des_dir");
	    $ftpmsg = $ftp->message;
    } elsif ($protocol eq "SFTP") {
        $cwd_rc = $ftp->setcwd("$bass1_ftp_basedir/$des_dir");
        $ftpmsg = $ftp->error;
    }

    if (!$cwd_rc )
    {
	 	showTime();print "Can't FIND Direcotry $des_dir:$ftpmsg\n";
	 	return 0;
	}
	my $del_rc;
    if ($protocol eq "FTP") {
        $del_rc = $ftp->delete("$des_file");
    } elsif ($protocol eq "SFTP") {
        $del_rc = $ftp->remove("$des_file");
    }

	unless($del_rc)
	{
	 	print "File $des_file delete failed:$!\n";
	 	return 0;
	}

	return 1;
}


# my $login_ftp = $args{user}.":".$args{password};
# print "login_ftp:". $login_ftp . "\n";
# my $sftp = Ftp_Connect("SFTP", $host, $args{port}, $login_ftp);

# my $deleteFlag = FTP_del_file("SFTP", $sftp, "/home/etl/Backup", "dir.hdc_20170905");
# print "deleteFlag:". ${deleteFlag} . "\n";


sub FTP_rename_file
{
	my($protocol,$ftp,$des_dir,$des_file) = @_;
	unless(@_ == 3)
	{
		print "parameter is not right\n";
		return 0;
	}

	unless($des_dir =~ m'^/.*')
	{
		$des_dir = "$des_dir";
	}

    my $cwd_rc;
    my $ftpmsg;
    if ($protocol eq "FTP") {
	    $cwd_rc = $ftp->cwd("$bass1_ftp_basedir/$des_dir");
	    $ftpmsg = $ftp->message;
    } elsif ($protocol eq "SFTP") {
        $cwd_rc = $ftp->setcwd("$bass1_ftp_basedir/$des_dir");
        $ftpmsg = $ftp->error;
    }

    if (!$cwd_rc )
    {
	 	showTime();print "Can't FIND Direcotry $des_dir:$ftpmsg\n";
	 	return 0;
	}
	my $del_rc;
    if ($protocol eq "FTP") {
        $del_rc = $ftp->rename("$des_file","APPDONE$des_file");
    } elsif ($protocol eq "SFTP") {
        $del_rc = $ftp->rename("$des_file","APPDONE$des_file");
    }

    unless($del_rc)
    {
	 	showTime();print "File $des_file delete failed:$!\n";
	 	return 0;
	}

	return 1;
}